import { Component, createRef } from "inferno";
import * as matrixcs from "matrix-js-sdk";
import * as localforage from "localforage";
import Header from "./ui/Header";
import TextInput from "./ui/TextInput";
import SoftKey from "./ui/SoftKey";
import TextListItem from "./ui/TextListItem";
import ListView from "./ListView";
import requestFunc from "./requestFunc";
import colors from "KaiUI/src/theme/colors.scss";

class Login extends Component {
  updateHomeServer = (evt) => {
    this.setState({ homeserver: evt.target.value });
  };

  updateUsername = (evt) => {
    this.setState({ username: evt.target.value });
  };

  updateLoginData = (evt) => {
    this.setState({ loginData: evt.target.value });
  };

  updateCursor = (cursor) => {
    this.setState({
      cursor: cursor,
    });
  };

  handleKeyDown = (evt) => {
    if (evt.key === "Backspace") {
      if (this.state.selectedLoginMethod) {
        this.setState({ selectedLoginMethod: "" });
        evt.preventDefault();
      } else if (this.state.loginFlows.length) {
        this.setState({ loginFlows: [] });
        evt.preventDefault();
      }
    }
  };

  doLogin = () => {
    if (this.state.loginData) {
      this.doLoginFinal();
    } else if (this.state.loginFlows.length === 0) {
      this.doLoginFlows();
    } else {
      this.doLoginData();
    }
  };

  doLoginFlows = () => {
    let homeserver, username;
    homeserver = this.state.homeserver;
    username = this.state.username;
    if (!homeserver || !username) {
      return;
    }
    if (!homeserver.startsWith("https://")) {
      homeserver = "https://" + homeserver;
    }
    window.mClient = matrixcs.createClient({
      baseUrl: homeserver,
      request: requestFunc,
    });
    window.mClient.loginFlows().then((result) => {
      this.setState({ loginFlows: result.flows });
    });
  };

  doLoginData = () => {
    const loginMethod = this.state.loginFlows[this.state.cursor];
    console.log(`[doLogindata] User wanna login with ${loginMethod.type}`);

    switch (loginMethod.type) {
      case "m.login.password":
        console.log("[doLoiginData] Logging in with password");
        this.setState({ selectedLoginMethod: "m.login.password" });
        break;
      default:
        alert("This login method is currently not supported :(");
        break;
    }
  };

  doLoginFinal = () => {
    switch (
      this.state.selectedLoginMethod // eslint-disable-line default-case
    ) {
      case "m.login.password":
        window.mClient
          .loginWithPassword(
            `@${this.state.username}:${this.state.homeserver}`,
            this.state.loginData
          )
          .then((result) => {
            localforage.setItem("login", result).then(() => {
              alert(`Logged in as ${this.state.username}`);
              window.location = window.location; // eslint-disable-line no-self-assign
            });
          })
          .catch((err) => {
            console.log("[doLoginFinal] Login Error", err.toString());
            switch (err.errcode) {
              case "M_FORBIDDEN":
                alert("Incorrect login credentials");
                break;
              case "M_USER_DEACTIVATED":
                alert("This user has been deactivated");
                this.setState({ loginData: null, loginFlows: [] });
                break;
              case "M_LIMIT_EXCEEDED":
                const retry = err.retry_after_ms / 1000;
                alert(`Too many requests! Please retry after ${retry} seconds`);
                break;
              default:
                alert("Login failed");
                break;
            }
          });
    }
  };

  constructor(props) {
    super(props);
    this.headerRef = createRef();
    this.listViewRef = createRef();
    this.state = {
      homeserver: "",
      username: "",
      loginFlows: [],
      selectedLoginMethod: "",
      loginData: null,
      cursor: 0,
    };

    this.listView = (
      <ListView
        cursor={0}
        cursorChangeCb={this.updateCursor}
        ref={this.listViewRef}
        $HasNonKeyedChildren
      >
        <TextInput
          label="Homeserver"
          placeholder="https://matrix.org"
          onChange={this.updateHomeServer}
          defaultValue={this.state.homeserver}
        />
        <TextInput
          label="Username"
          placeholder="somebody"
          onChange={this.updateUsername}
          defaultValue={this.state.username}
        />
      </ListView>
    );
    this.header = (
      <Header
        text={""}
        backgroundColor={colors.headerBlue}
        ref={this.headerRef}
      />
    );
  }

  componentWillUpdate(nextProps, nextState, context) {
    if (nextState.selectedLoginMethod) {
      switch (nextState.selectedLoginMethod) {
        case "m.login.password":
          this.headerRef.current.setState({ text: "Login with password" });
          this.listViewRef.current.resetChildrenCursor([
            <TextInput
              label="Password"
              fieldType="password"
              placeholder="HG#$@B#@#G%N&*"
              onChange={this.updateLoginData}
            />,
          ]);
          break;
        default:
          break;
      }
    } else if (nextState.loginFlows.length) {
      if (this.headerRef.current.state.text === "Login method") return;
      this.headerRef.current.setState({ text: "Login method" });
      this.listViewRef.current.resetChildrenCursor(
        nextState.loginFlows.map((item) => <TextListItem primary={item.type} />)
      );
    }
  }

  render() {
    if (this.state.loginFlows.length === 0) {
      this.headerRef.current &&
        this.headerRef.current.setState({ text: "Login" });
    }

    return (
      <div>
        {this.header}
        {this.listView}
        <footer $HasVNodeChildren>
          <SoftKey
            leftText="Quit"
            leftCb={() => window.close()}
            centerCb={this.doLogin}
            centerText="Login"
          />
        </footer>
      </div>
    );
  }
}

export default Login;
